package com.ming.common.liteflow.core.exec;

import cn.hutool.core.thread.ThreadUtil;
import com.ming.common.dynamic.code.IClassExecuter;
import com.ming.common.dynamic.code.IStringCompiler;
import com.ming.common.dynamic.code.RunSourceHandler;
import com.ming.common.dynamic.code.config.RunSourceProperties;
import com.ming.common.dynamic.code.core.ClassExecuter;
import com.ming.common.dynamic.code.core.JaninoCompiler;
import com.ming.common.dynamic.code.dto.ExecuteResult;
import com.ming.common.dynamic.code.dto.Parameters;
import com.ming.common.init.LogInit;
import com.ming.common.liteflow.context.IvyLoadCmp;
import com.ming.common.liteflow.core.dynamic.IvyDynamicClass;
import com.ming.common.liteflow.core.node.SpringBeanUtil;
import com.ming.common.liteflow.vo.IvyDynamicClassVo;
import com.ming.common.util.FileUtil;
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ClassExecUtil {

    private static final Logger LOG = LoggerFactory.getLogger(ClassExecUtil.class);

    private static final Map<String,Integer> dynamicClassMap = new HashMap<>();

    public static Map<String,Object> execCmp(IvyDynamicClass item,String sourceCode){
        String beanName = item.getSourceClassName();
        dynamicClassMap.putIfAbsent(beanName,item.getVersion());
        // 判断源码是否发生变化
        if(!item.getSourceCode().equals(sourceCode)){ // 不一致
            item.setSourceCode(sourceCode);
            Integer version = dynamicClassMap.get(beanName);
            version = version + 1;
            item.setVersion(version);
            dynamicClassMap.put(beanName, version);
        }

        String cmpId = item.getSourceCmpId();
        beanName = beanName + item.getVersion();

        Class<?> cmpClass = ClassExecUtil.compilerCmp(item);

        /*cmpClass = IvyMethodMonitor.monitorClass(cmpClass);

        try {
            Object o = cmpClass.newInstance();

            Method process = ClassUtil.getDeclaredMethod(cmpClass, "process");
            Object invoke = MethodHandleUtil.invoke(o, process);

        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }*/

        long ms = System.currentTimeMillis();
        String startKey = ms + LogInit.startKey;
        String endKey = ms + LogInit.endKey;
        LOG.info(startKey);

        try {
            if(SpringBeanUtil.getBean(beanName) == null){
                SpringBeanUtil.registerBean(beanName,cmpClass);
            }
        }catch (Exception e){
            SpringBeanUtil.registerBean(beanName,cmpClass);
        }

        String key = item.getClassType() + (item.getIsFallback() == null ? "" : item.getIsFallback().toString());
        LiteFlowNodeBuilder builder = LiteFlowNodeBuilder.createCommonNode();
        switch (key){
            case "11":
            case "10": builder = LiteFlowNodeBuilder.createCommonNode();break;//普通组件类
            case "21":
            case "20": builder = LiteFlowNodeBuilder.createSwitchNode();break;//选择组件类
            case "31":
            case "30": builder = LiteFlowNodeBuilder.createIfNode();break;//条件组件类
            case "41":
            case "40": builder = LiteFlowNodeBuilder.createForNode();break;//次数循环组件类
            case "51":
            case "50": builder = LiteFlowNodeBuilder.createWhileNode();break;//条件循环组件类
            case "61":
            case "60": builder = LiteFlowNodeBuilder.createIteratorNode();break;//迭代循环组件类
            case "71":
            case "70": builder = LiteFlowNodeBuilder.createBreakNode();break;//退出循环组件类
        }
        builder.setId(cmpId).setName(item.getClassName()).setClazz(item.getPackagePath()+"."+beanName).build();
//        builder.setId(cmpId).setName(item.getClassName()).setClazz(cmpClass).build();
        String el = "THEN(node(\""+cmpId+"\")"+")";
        String returnVal = ELExecUtil.exec(el,false);

        LOG.info(endKey);
        List<String> list = LogInit.logMap.get(endKey);
        while (list == null || list.isEmpty()) {
            list = LogInit.logMap.get(endKey);// 等待list不为空
            ThreadUtil.sleep(100);
        }
        LogInit.logMap.remove(endKey);
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("returnVal", returnVal);
        resultMap.put("logStr", String.join(System.lineSeparator(),list));
        return resultMap;
    }

    public static Map<String,Object> execCommon(IvyDynamicClassVo vo) throws Exception {
        Map<String, String> hackers = new HashMap<>();
        RunSourceProperties calTime = new RunSourceProperties();
        calTime.setCalCompileTime(true);
        IStringCompiler compiler = new JaninoCompiler();
        IClassExecuter<ExecuteResult> executer = new ClassExecuter();
        RunSourceHandler handler = new RunSourceHandler(compiler, executer, calTime, hackers);

        long ms = System.currentTimeMillis();
        String startKey = ms + LogInit.startKey;
        String endKey = ms + LogInit.endKey;

        LOG.info(startKey);
        ExecuteResult result = null;
        try {
            Parameters pars = new Parameters();
            Object[] params = vo.getParams();
            if(params != null){
                for (int i=0;i<params.length;i++){
                    pars.add(params[i]);
                }
            }
            String packagePath = "";
            if(!vo.getSourceCode().startsWith("package")){
                packagePath = "package "+vo.getPackagePath()+";";
            }
            // 重新编译加载源码类
            result = handler.runMethod(packagePath+vo.getSourceCode(), vo.getMethodName(), pars, false, true);
        }catch (Exception e){
            e.printStackTrace();
            System.out.println(e.getMessage());
            StackTraceElement[] stackTrace = e.getStackTrace();
            List<String> list = new ArrayList<>();
            for (StackTraceElement element : stackTrace){
                list.add(element.toString());
            }
            System.out.println(String.join(System.lineSeparator(),list));
        }
        LOG.info(endKey);

        List<String> list = LogInit.logMap.get(endKey);
        while (list == null || list.isEmpty()) {
            list = LogInit.logMap.get(endKey);// 等待list不为空
            ThreadUtil.sleep(100);
        }
        LogInit.logMap.remove(endKey);
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("returnVal", result != null ? String.valueOf(result.getReturnVal()) : "null");
        resultMap.put("logStr", String.join(System.lineSeparator(),list));
        return resultMap;
    }

    public static Class<?> buildCmp(IvyDynamicClass item){
        String beanName = item.getSourceClassName();
        dynamicClassMap.putIfAbsent(beanName,item.getVersion());
        // 判断源码是否发生变化
        if(!item.getSourceCode().equals(item.getSourceCode())){ // 不一致
            item.setSourceCode(item.getSourceCode());
            Integer version = dynamicClassMap.get(beanName);
            version = version + 1;
            item.setVersion(version);
            dynamicClassMap.put(beanName, version);
        }
        return ClassExecUtil.compilerCmp(item);
    }

    public static Class<?> compilerCmp(IvyDynamicClass ivyDynamicClass) {
        String root = ClassUtils.getDefaultClassLoader().getResource("").getPath();
        String className = ivyDynamicClass.getSourceClassName()+ivyDynamicClass.getVersion();
        String packagePath = String.join(File.separator,ivyDynamicClass.getPackagePath().split("\\."));
        String rootPath = root+packagePath;
        String forName = ivyDynamicClass.getPackagePath()+"."+className;
        String sourceCode = ivyDynamicClass.getSourceCode();

        Pattern pattern = Pattern.compile("class\\s+(\\w+)");
        Matcher matcher = pattern.matcher(sourceCode);
        sourceCode = matcher.replaceAll("class " + className);

        pattern = Pattern.compile("@LiteflowComponent\\(\"([^\"]+)\"\\)");
        matcher = pattern.matcher(sourceCode);
        sourceCode = matcher.replaceAll("@LiteflowComponent(\"" + className+"\")");
        sourceCode = sourceCode.replaceAll(ivyDynamicClass.getSourceClassName()+".class",className+".class");

        Class<?> dynamicClass = null;
        try {
            // 检查并创建根路径
            File rootDir = new File(rootPath);
            if (!rootDir.exists()) {
                if (!rootDir.mkdirs()) {
                    System.err.println("无法创建动态class目录");
                    System.exit(1);
                }
            }

            String fileClassName = className + ".class";
            String fileJavaName = className + ".java";
            FileUtil.removeFile(rootPath,fileClassName,fileJavaName);

            // 确保输出目录存在
            File outputDir = new File(root);

            // 保存源码到文件
            File sourceFile = new File(rootDir, className + ".java");
            FileWriter writer = new FileWriter(sourceFile);
            writer.write(sourceCode);
            writer.close();

            // 获取系统编译器
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

            // 获取文件管理器
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

            // 获取编译单元
            Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(sourceFile));

            // 设置编译参数
            Iterable<String> options = Arrays.asList("-d", outputDir.getAbsolutePath());

            // 创建编译任务
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, compilationUnits);

            // 执行编译任务
            boolean success = task.call();

            if (success) {
                // 加载编译后的类
                URLClassLoader classLoader = new URLClassLoader(new URL[]{new File(root).toURI().toURL()});
                dynamicClass = Class.forName(forName, true, classLoader);

                // 创建实例并调用方法
                //Object instance = dynamicHelloClass.getDeclaredConstructor().newInstance();
                //dynamicHelloClass.getMethod(methodName).invoke(instance);
            }

            // 关闭文件管理器
            fileManager.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dynamicClass;
    }

    public static String getClassName(String sourceCode){
        Pattern pattern = Pattern.compile("class\\s+(\\w+)");
        Matcher matcher = pattern.matcher(sourceCode);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    public static String getCmpId(String sourceCode){
        Pattern pattern = Pattern.compile("@LiteflowComponent\\(\"([^\"]+)\"\\)");
        Matcher matcher = pattern.matcher(sourceCode);
        if (matcher.find()) {
            return  matcher.group(1);
        }
        return null;
    }

    public static String getPackagePath(String sourceCode){
        // 定义正则表达式匹配包名
        String packageNameRegex = "\\bpackage\\s+([\\w.]+)\\s*;";
        // 编译正则表达式
        Pattern pattern = Pattern.compile(packageNameRegex);
        // 创建 Matcher 对象并匹配源代码
        Matcher matcher = pattern.matcher(sourceCode);
        // 提取包名
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

}
